home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 February
/
EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso
/
earcd
/
comm2
/
kms20src.lha
/
KMSS
/
rexx.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-03
|
13KB
|
450 lines
/**********************************
* KMS *
**********************************
* ©1993 by BlackMagic Software *
**********************************
* *
**********************************/
#include <KMS/KMS.h>
#include <KMS/KMS_devlib.h>
#include <KMS/KMS_rexx.h>
Prototype ULONG upRexxPort(STRPTR, struct rexxCommandList *, STRPTR, VOID (*)());
Prototype VOID dnRexxPort(VOID);
Prototype VOID dispRexxPort(VOID);
Prototype struct RexxMsg *sendRexxCmd(STRPTR, APTR, STRPTR, STRPTR, STRPTR, STRPTR);
Prototype VOID replyRexxCmd(struct RexxMsg *, ULONG, STRPTR);
Prototype BOOL SetARexxLastError(struct RexxMsg *, STRPTR);
Prototype UBYTE OpenRexxLib(VOID);
Prototype VOID CloseRexxLib(VOID);
/******* Alles folgende auf Grundlage von... *******/
static STRPTR blurb = "Radical Eye MinRexx 0.4";
/***************************************************/
// Local Prototypes
static UWORD CmdCmp(STRPTR, STRPTR);
static VOID (*UserDisp)(struct RexxMsg *, struct rexxCommandList *, STRPTR);
static VOID ReplyToIt(register struct RexxMsg *);
// Variables
struct MsgPort *MyRexxPort = NULL; /* this is *our* rexx port */
int BringerDown = 0; /* are we trying to shut down? */
struct rexxCommandList *GlobalRCL = NULL; /* our command association list */
ULONG StillNeedReplies = 0; /* how many replies are pending? */
ULONG RexxPortBit = 0; /* what bit to wait on for Rexx? */
STRPTR Extension = NULL; /* the Extension for macros */
struct RexxMsg *ORexxMsg = NULL; /* the outstanding Rexx message */
struct RexxMsg *MeetMessage = NULL; /* Auf diese wird gewartet */
static TEXT dbtext[160]; /* Für Debugging-Zwecke */
// Our library base. Don't you dare close this!
struct RxsLib *RexxSysBase;
/*
* upRexxPort() returns the signal bit to wait on for Rexx messages.
* If something goes wrong, it simply returns a `0'. Note that this
* function is safe to call multiple times because we check to make
* sure we haven't opened already. It's also a quick way to change
* the association list or dispatch function.
*/
ULONG upRexxPort(STRPTR s, struct rexxCommandList *rcl, STRPTR exten, VOID (*uf)())
{
if (rcl == NULL || uf == NULL)
return 0;
BringerDown = 0;
if(MyRexxPort == NULL)
{
Forbid();
if (FindPort(s) == NULL)
MyRexxPort = CreatePort(s, 0);
Permit();
if (MyRexxPort != NULL)
RexxPortBit = (1L << MyRexxPort->mp_SigBit);
}
GlobalRCL = rcl;
Extension = exten;
UserDisp = uf;
return RexxPortBit;
}
/*
* This function closes the rexx library, but only if it is open
* and we aren't expecting further replies from REXX. It's
* *private*, but it doesn't have to be; it's pretty safe to
* call anytime.
*/
VOID CloseRexxLib(VOID)
{
if(StillNeedReplies == 0 && RexxSysBase)
{
CloseLibrary((struct Library *)RexxSysBase);
RexxSysBase = NULL;
}
}
/*
* This function closes down the Rexx port. It is always safe to
* call, and should *definitely* be made a part of your cleanup
* routine. No arguments and no return. It removes the Rexx port,
* replies to all of the messages and insures that we get replies
* to all the ones we sent out, closes the Rexx library, deletes the
* port, clears a few flags, and leaves.
*/
VOID dnRexxPort(VOID)
{
if(MyRexxPort)
{
RemPort(MyRexxPort);
BringerDown = 1;
/*
* A message still hanging around? We kill it off.
*/
if(ORexxMsg)
{
ORexxMsg->rm_Result1 = RXERRORIMGONE;
ReplyMsg((struct Message *)ORexxMsg);
ORexxMsg = NULL;
}
dispRexxPort();
while(StillNeedReplies)
{
WaitPort(MyRexxPort);
dispRexxPort();
}
CloseRexxLib();
DeletePort(MyRexxPort);
MyRexxPort = NULL;
}
RexxPortBit = 0;
}
/*
* Here we dispatch any REXX messages that might be outstanding.
* This is the main routine for handling Rexx messages.
* This function is fast if no messages are outstanding, so it's
* pretty safe to call fairly often.
*
* If we are bring the system down and flushing messages, we reply
* with a pretty serious return code RXERRORIMGONE.
*
* No arguments, no returns.
*/
VOID dispRexxPort(VOID)
{
register struct RexxMsg *rexxmsg;
register struct rexxCommandList *rcl;
register STRPTR p;
register UBYTE dontreply;
/*
* If there's no rexx port, we're out of here.
*/
if(MyRexxPort == NULL)
return;
/*
* Otherwise we have our normal loop on messages.
*/
while(rexxmsg = (struct RexxMsg *)GetMsg(MyRexxPort))
{
/*
* If we have a reply to a message we sent, we look at the second
* argument. If it's set, it's a function we are supposed to call
* so we call it. Then, we kill the argstring and the message
* itself, decrement the outstanding count, and attempt to close
* down the Rexx library. Note that this call only succeeds if
* there are no outstanding messages. Also, it's pretty quick, so
* don't talk to me about efficiency.
*/
if(rexxmsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG)
{
VOID (*replytoit)(register struct RexxMsg *);
/*
sprintf(dbtext, "Reply received: Result1= %8lx Result2= %8lx\n", rexxmsg->rm_Result1, rexxmsg->rm_Result2);
Out(dbtext);
*/
if(rexxmsg->rm_Args[1])
{
replytoit = rexxmsg->rm_Args[1];
replytoit(rexxmsg);
}
DeleteArgstring(rexxmsg->rm_Args[0]);
DeleteRexxMsg(rexxmsg);
StillNeedReplies--;
CloseRexxLib();
}
else
{
/*
* The default case is we got a message and we need to check it for
* primitives. We skip past any initial tabs or spaces and initialize
* the return code fields.
*/
p = (STRPTR)rexxmsg->rm_Args[0];
while (*p && *p <= ' ')
p++;
/*
if(rexxmsg->rm_Args[2])
sprintf(dbtext, "Commd from %02d : [%s]\n", rexxmsg->rm_Args[2], p);
else
sprintf(dbtext, "Commd from ?? : [%s]\n", p);
Out(dbtext);
*/
rexxmsg->rm_Result1 = 0;
rexxmsg->rm_Result2 = 0;
/*
* If somehow the reply is already done or postponed, `dontreply' is
* set.
*/
dontreply = 0;
/*
* If the sky is falling, we just blow up and replymsg.
*/
if(BringerDown)
rexxmsg->rm_Result1 = RXERRORIMGONE;
else
{
/*
* Otherwise we search down our association list, comparing commands,
* until we get a match. If we get a match, we call the dispatch
* function with the appropriate arguments, and break out.
*/
ORexxMsg = rexxmsg;
for(rcl = GlobalRCL; rcl->name; rcl++)
{
if(CmdCmp(rcl->name, p) == 0)
{
UserDisp(rexxmsg, rcl, p+strlen(rcl->name));
break;
}
}
/*
* If we broke out, rcl will point to the command we executed; if we
* are at the end of the list, we didn't understand the command. In
* this case, if we were supplied an extension in upRexxPort, we know
* that we should send the command out, so we do so, asynchronously.
* The asynchronous send takes care of our reply. If we were given a
* NULL extension, we bitch that the command didn't make sense to us.
*/
if(rcl->name == NULL)
{
if(Extension)
{
sendRexxCmd(rexxmsg->rm_Args[0], (APTR)&ReplyToIt, (STRPTR)rexxmsg, NULL, NULL, NULL);
dontreply = 1;
}
else
rexxmsg->rm_Result1 = RXERRORNOCMD;
}
}
/*
* Finally, reply if appropriate.
*/
ORexxMsg = NULL;
if(!dontreply)
ReplyMsg((struct Message *)rexxmsg);
}
}
}
/*
* This is the function we use to see if the command matches
* the command string. Not case sensitive.
* Make sure all commands in the rexxCommandList are given in lower case!
*/
static UWORD CmdCmp(register STRPTR c, register STRPTR m)
{
while(*c && ((*c == *m) || (*c == *m + 32 && ('a' <= *c && *c <= 'z'))))
{
c++;
m++;
}
if(*m != ' ' && *m != '\0')
return 1;
return *c;
}
/*
* Opens the Rexx library if unopened. Returns success (1) or
* failure (0). This is another function that is *private* but
* that doesn't have to be.
*/
UBYTE OpenRexxLib(VOID)
{
if(RexxSysBase)
return 1;
return (UBYTE)((RexxSysBase = (struct RxsLib *)OpenLibrary(RXSNAME, 0L)) != NULL);
}
/*
* This is the general ARexx command interface, but is not the one
* you will use most of the time; ones defined later are easier to
* understand and use. But they all go through here.
*/
struct RexxMsg *sendRexxCmd(STRPTR s, APTR f, STRPTR p1, STRPTR p2, STRPTR p3, STRPTR port)
{
register struct MsgPort *rexxport;
register struct RexxMsg *rexxmsg;
/*
sprintf(dbtext, "Sending Command: [%s] to [%s]\n", s, port);
Out(dbtext);
*/
if (MyRexxPort == NULL || StillNeedReplies > MAXRXOUTSTANDING-1)
return NULL;
rexxmsg = NULL;
if(OpenRexxLib()
&& (rexxmsg = CreateRexxMsg(MyRexxPort, Extension, MyRexxPort->mp_Node.ln_Name))
&& (rexxmsg->rm_Args[0] = CreateArgstring(s, (ULONG)strlen(s))))
{
rexxmsg->rm_Action = RXCOMM;
rexxmsg->rm_Args[1] = (STRPTR)f;
rexxmsg->rm_Args[2] = NULL; /* Sending KMS-Port */
rexxmsg->rm_Args[3] = p1;
rexxmsg->rm_Args[4] = p2;
rexxmsg->rm_Args[5] = p3;
if(port)
rexxmsg->rm_Node.mn_Node.ln_Name = port;
else
rexxmsg->rm_Node.mn_Node.ln_Name = RXSDIR;
Forbid();
if(port)
rexxport = FindPort(port);
else
rexxport = FindPort(RXSDIR);
if(rexxport)
PutMsg(rexxport, (struct Message *)rexxmsg);
Permit();
if(rexxport)
{
StillNeedReplies++;
return rexxmsg;
}
else
DeleteArgstring(rexxmsg->rm_Args[0]);
}
if(rexxmsg)
DeleteRexxMsg(rexxmsg);
CloseRexxLib();
return NULL;
}
/*
* This function sets things up to reply to the message that caused
* it when we get a reply to the message we are sending out here.
* But first the function we pass in, which actually handles the reply.
* Note how we get the message from the Args[3]; Args[0] is the command,
* Args[1] is this function, and Args[3]..Args[5] are any parameters
* passed to sendRexxCmd() as p1..p3. We pass the result codes right
* along.
*/
static VOID ReplyToIt(register struct RexxMsg *msg)
{
register struct RexxMsg *omsg;
omsg = (struct RexxMsg *)(msg->rm_Args[3]);
replyRexxCmd(omsg, msg->rm_Result1, NULL);
ReplyMsg((struct Message *)omsg);
}
/*
* This function passes back an errorcode or a return string.
*/
VOID replyRexxCmd(struct RexxMsg *msg, ULONG errorcode, STRPTR string)
{
ULONG secondary = 0;
if(errorcode == 0 && (msg->rm_Action & RXFF_RESULT))
{
if(string && OpenRexxLib())
secondary = (ULONG)CreateArgstring(string, (ULONG)strlen(string));
else
secondary = 0;
}
else if(errorcode == 0 && string)
secondary = (ULONG)string;
msg->rm_Result1 = errorcode;
msg->rm_Result2 = secondary;
CloseRexxLib();
}
/*
* This function will set an error string for the ARexx
* application in the variable defined as <appname>.LASTERROR
*
* Note that this can only happen if there is an ARexx message...
*
* This returns TRUE if it worked, FALSE if it did not...
*/
BOOL SetARexxLastError(struct RexxMsg *rmsg, STRPTR errorstring)
{
STRPTR errorname = "KMS.LASTERROR";
if(rmsg)
{
if(!SetRexxVar((struct Message *)rmsg, errorname, errorstring, (ULONG)strlen(errorstring)))
return TRUE;
}
return FALSE;
}